/**
 * 文件名:  IDEUtils.java
 * 版权:    Copyright 2000-2010 Huawei Tech. Co. Ltd. All Rights Reserved.
 * 创建人:  005828
 * 文件描述:  
 * 修改时间: 2010-6-21 上午09:22:14
 * 修改内容： 新增
 */
package com.huawei.virest.common.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.xml.rpc.ServiceException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * 
 * 类描述：
 * 
 * @author 005828
 * @version ITMS-OnlineUpdate V300R001
 */
public class Utils
{
    private static Log logger = LogFactory.getLog(Utils.class);
    
    /**
     * 
     * 方法表述
     * @param date date
     * @return Timestamp
     * @throws JSONException 解析异常
     */
    @SuppressWarnings("deprecation")
    public static Timestamp formatDate(String date) throws JSONException
    {
        Timestamp timestamp = null;
        
        if (isNumber(date))
        {
            timestamp = getTimestamp(Long.parseLong(date));
        }
        else if (isDateFormat(date) || isDatetimeFormat(date))
        {
            timestamp = (Timestamp)parseRFC3339Date(date);
        }
        else if (isSimpleDateFormat(date))
        {
            timestamp = getTimestamp(parseDate(date).getTime());
        }
        else
        {
            timestamp = getTimestamp(Date.parse(date));
        }
        
        return timestamp;
    }
    
    /**
     * 判断字符串是否为空
     * @param str str
     * @return boolean
     */
    public static boolean isNull(String str)
    {
        return (null == str || "".equals(str.trim())) ? true : false;
    }
    
    /**
     * 判断列表是否为空
     * @param list list
     * @return boolean
     */
    public static boolean isListNull(List<?> list)
    {
        return list == null || list.isEmpty();
    }
    
    /**
     * 判断列表是否为空
     * @param obj obj
     * @return boolean
     */
    public static boolean isObjectNull(Object obj)
    {
        return obj == null;
    }
    
    /**
     * getQueryParamFromObject
     * @param obj obj
     * @return String
     * @throws ServiceException ServiceException
     */
    @SuppressWarnings("unchecked")
    public static String getQueryParamFromObject(Object obj) throws Exception
    {
        StringBuffer attachment = new StringBuffer();
        Class paramClass = obj.getClass();
        
        try
        {
            Field[] fields = paramClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++)
            {
                Field field = fields[i];
                String name = field.getName();
                
                String methodName = "get" + getCapitalToUpperCase(name);
                Method method;
                method = paramClass.getMethod(methodName, new Class[] {});
                Object value = method.invoke(obj, new Object[] {});
                if (value != null && !"".equals(value))
                {
                    attachment.append(name + "=" + value + "&");
                }
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.getMessage());
        }
        
        if (attachment.length() > 0)
        {
            attachment.insert(0, "?");
            attachment.setLength(attachment.length() - 1);
        }
        
        return attachment.toString();
    }
    
    /**
     * setValueToObject
     * @param <T> T
     * @param clazz clazz
     * @param map map
     * @return t
     * @throws Exception Exception
     */
    public static <T> T setValueToObject(Class<T> clazz, Map<String, String> map)
            throws Exception
    {
        Map<String, String> params = map;
        
        T t;
        try
        {
            t = clazz.getConstructor(new Class[] {})
                    .newInstance(new Object[] {});
        }
        catch (Exception e)
        {
            throw new Exception(e.getMessage());
        }
        
        try
        {
            Field[] fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++)
            {
                String name = fields[i].getName();
                String value = params.get(name);
                
                if (params.containsKey(name) && Utils.isNull(value))
                {
                    logger.info("Request parameters is invalid");
                    throw new Exception("REQUEST_PARAMETERS_INVALID");
                }
                
                if (params.containsKey(name))
                {
                    params.remove(name);
                    
                    String methodName = "set" + getCapitalToUpperCase(name);
                    
                    Method method = clazz.getMethod(methodName,
                            new Class[] {fields[i].getType()});
                    
                    method.invoke(t, new Object[] {castType(name,
                            fields[i].getType().getSimpleName(),
                            value)});
                }
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.getMessage());
        }
        
        if (params.size() > 0)
        {
            logger.info("Request parameters is invalid");
            throw new Exception("REQUEST_PARAMETERS_INVALID"
                    + params.keySet().iterator().next());
        }
        
        logger.info("Output Request Query Parameter");
        
        return t;
    }
    
    private static Object castType(String fieldName, String typeName,
            String value) throws Exception
    {
        Object obj = value;
        try
        {
            // type.getName()
            if (typeName.equals("Integer"))
            {
                obj = Integer.parseInt(value);
            }
            else if (typeName.equals("Long"))
            {
                obj = Long.parseLong(value);
            }
            else if (typeName.equals("Float"))
            {
                obj = Float.parseFloat(value);
            }
            else if (typeName.equals("Double"))
            {
                obj = Double.parseDouble(value);
            }
            else if (typeName.equals("Short"))
            {
                obj = Short.parseShort(value);
            }
            
        }
        catch (NumberFormatException e)
        {
            throw new Exception("MALFORMED_REQUEST_PARAMETERS" + fieldName);
        }
        
        return obj;
    }
    
    /**
     * getCapitalToLowerCase
     * @param obj obj
     * @return String
     */
    public static String getCapitalToLowerCase(Object obj)
    {
        String classname = obj.getClass().getSimpleName();
        return classname.substring(0, 1).toLowerCase() + classname.substring(1);
    }
    
    /**
     * getCapitalToLowerCase
     * @param clazz clazz
     * @return String
     */
    @SuppressWarnings("unchecked")
    public static String getCapitalToLowerCase(Class clazz)
    {
        String classname = clazz.getSimpleName();
        return classname.substring(0, 1).toLowerCase() + classname.substring(1);
    }
    
    /**
     * getCapitalToUpperCase
     * @param name name
     * @return String
     */
    public static String getCapitalToUpperCase(String name)
    {
        return name.substring(0, 1).toUpperCase() + name.substring(1);
    }
    
    /**
     * <一句话功能简述> <功能详细描述>
     * @param fileName FileName
     * @return [参数说明]
     * @see [类、类#方法、类#成员]
     */
    public static String getResponseFromFile(String fileName)
    {
        StringBuffer sb = new StringBuffer();
        BufferedReader br = null;
        try
        {
            File file = new File(fileName);
            br = new BufferedReader(new FileReader(file));
            String str1 = "";
            while ((str1 = br.readLine()) != null)
            {
                sb.append(str1);
            }
        }
        catch (Exception e)
        {
            logger.info("读取文件发生错误");
        }
        finally
        {
            if (br != null)
            {
                try
                {
                    br.close();
                }
                catch (IOException e)
                {
                    logger.error("getResponseFromFile() close stream exception");
                }
            }
        }
        return sb.toString();
    }
    
    /**
     * 设置map
     * @param map map
     * @param object object
     * @return map
     * @throws Exception Exception
     */
    @SuppressWarnings("unchecked")
    public static Map<String, String> setValueToMap(Map<String, String> map,
            Object object) throws Exception
    {
        Class cls = object.getClass();
        
        Field[] fields = cls.getDeclaredFields();
        
        try
        {
            for (int i = 0; i < fields.length; i++)
            {
                Field field = fields[i];
                
                String methodName = "get"
                        + getCapitalToUpperCase(field.getName());
                Method method = cls.getMethod(methodName, new Class[] {});
                
                Object obj = method.invoke(object, new Object[] {});
                
                map.put(field.getName(), obj.toString());
            }
        }
        catch (Exception e)
        {
            throw new Exception("SERVER_ERROR");
        }
        
        return map;
    }
    
    /**
     * 
     * 方法表述: 判断是否是数字
     * @param str str
     * @return boolean
     */
    public static boolean isNumber(String str)
    {
        if (isNull(str))
        {
            return false;
        }
        return Pattern.matches("[0-9|\\.]*", str);
    }
    
    /**
     * 日期格式检查 如：
     * @param datetime 日期字符串
     * @return boolean true 日期格式正确，false 日期格式不正确
     */
    public static boolean isDatetimeFormat(String datetime)
    {
        String regex = "^(\\d{4})-(0\\d{1}|1[0-2])-(0\\d{1}|[12]\\d{1}|3[01])T"
                + "(0\\d{1}|1\\d{1}|2[0-3]):[0-5]\\d{1}:([0-5]\\d{1})(\\.\\d{0,3}){0,1}"
                + "(Z|[\\+|\\-](0\\d{1}|1\\d{1}|2[0-3]):[0-5]\\d{1})$";
        return Pattern.matches(regex, datetime);
    }
    
    /**
     * RFC 3339日期格式校验
     * @param datetime 日期字符串
     * @return boolean true 日期格式正确，false 日期格式不正确
     */
    public static boolean isDateFormat(String datetime)
    {
        String date = "(\\d{4})-(0\\d{1}|1[0-2])-(0\\d{1}|[12]\\d{1}|3[01])T"
                + "(0\\d{1}|1\\d{1}|2[0-3]):[0-5]\\d{1}:([0-5]\\d{1})(Z|.[0-9]{2}Z|[-|+][0-5]\\d{0,8})";
        return Pattern.matches(date, datetime);
    }
    
    /**
     * 简单日期格式校验
     * @param datetime 日期字符串
     * @return boolean true 日期格式正确，false 日期格式不正确
     */
    public static boolean isSimpleDateFormat(String datetime)
    {
        String date = "(\\d{4})-(0\\d{1}|1[0-2])-(0\\d{1}|[12]\\d{1}|3[01]) "
                + "(0\\d{1}|1\\d{1}|2[0-3]):[0-5]\\d{1}:([0-5]\\d{1})";
        return Pattern.matches(date, datetime);
    }
    
    /**
     * 把RFC 3339格式的时间转换成毫秒值
     * @param date 时间
     * @return Long 结果值
     */
    public static long parseDateToMillionSeconds(String date)
    {
        long millionSeconds = 0;
        
        try
        {
            millionSeconds = formatDate(date).getTime();
        }
        catch (JSONException e)
        {
            logger.error("Datetime Parse Exception! " + e.getCause());
        }
        
        return millionSeconds;
    }
    
    /**
     * 时间格式转换
     * @param date String
     * @return Date
     * @throws JSONException [参数说明]
     * @see [类、类#方法、类#成员]
     */
    public static Date parseRFC3339Date(String date) throws JSONException
    {
        Date d = new Date();
        
        try
        {
            //if there is no time zone, we don't need to do any special parsing.
            if (date.endsWith("Z"))
            {
                try
                {
                    SimpleDateFormat s = new SimpleDateFormat(
                            "yyyy-MM-dd'T'HH:mm:ss'Z'");//spec for RFC3339                    
                    d = s.parse(date);
                }
                catch (java.text.ParseException pe)
                {
                    //try again with optional decimals
                    SimpleDateFormat s = new SimpleDateFormat(
                            "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'");//spec for RFC3339 (with fractional seconds)
                    s.setLenient(true);
                    d = s.parse(date);
                }
                return new Timestamp(d.getTime());
            }
            else if (date.lastIndexOf(':') > 19)
            {
                //step one, split off the timezone. 
                String split = "-";
                if (date.lastIndexOf('+') > 10)
                {
                    split = "+";
                }
                String firstpart = date.substring(0, date.lastIndexOf(split));
                String secondpart = date.substring(date.lastIndexOf(split));
                
                //step two, remove the colon from the timezone offset
                secondpart = secondpart.substring(0, secondpart.indexOf(':'))
                        + secondpart.substring(secondpart.indexOf(':') + 1);
                date = firstpart + secondpart;
            }
            else
            {
                SimpleDateFormat s = new SimpleDateFormat(
                        "yyyy-MM-dd'T'HH:mm:ssZ");//spec for RFC3339      
                try
                {
                    d = s.parse(date);
                }
                catch (java.text.ParseException pe)
                {
                    //try again with optional decimals
                    //spec for RFC3339 (with fractional seconds)
                    s = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ");
                    s.setLenient(true);
                    d = s.parse(date);
                }
            }
        }
        catch (ParseException e)
        {
            throw new JSONException("JSON_FORMAT_CONVERSION_FAILED");
        }
        
        return d;
    }
    
    /**
     * 如果返回的是否为Restult错误结构体
     * 
     * @author hpli/025415
     * @param retStr retStr
     * @return boolean
     */
    public static boolean hasIsResult(String retStr)
    {
        boolean bool = false;
        
        try
        {
            JSONObject jsonObj = new JSONObject(retStr);
            if (jsonObj.has("result"))
            {
                bool = true;
            }
        }
        catch (JSONException e)
        {
            e.printStackTrace();
        }
        
        return bool;
    }
    
    /**
     * 判断是否为int类型
     * 
     * @param temp 判断是否为int型数据对象
     * @return [参数说明]
     * 
     * @see [类、类#方法、类#成员]
     * @author 025415/hpli
     */
    public static boolean isInteger(String temp)
    {
        try
        {
            // 强转为Integer类型
            Integer.parseInt(temp);
        }
        catch (Exception e)
        {
            return false;
        }
        return true;
    }
    
    /**
     * 判断是否为Long类型
     * 
     * @param temp 判断是否为Long型数据对象
     * @return [参数说明]
     * 
     * @see [类、类#方法、类#成员]
     * @author 025415/hpli
     */
    public static boolean isLong(String temp)
    {
        try
        {
            // 强转为Long类型
            Long.parseLong(temp);
        }
        catch (Exception e)
        {
            return false;
        }
        return true;
    }
    
    /**
     * 判断是否为Long类型
     * 
     * @param temp 判断是否为Long型数据对象
     * @return [参数说明]
     * 
     * @see [类、类#方法、类#成员]
     * @author 025415/hpli
     */
    public static boolean isFloat(String temp)
    {
        try
        {
            // 强转为Float类型
            Float.parseFloat(temp);
        }
        catch (Exception e)
        {
            return false;
        }
        return true;
    }
    
    /**
     * 获得系统当前时间
     * @return String [返回类型说明]
     * @see [类、类#方法、类#成员]
     */
    public static String getDatetime()
    {
        return formatDate(new Date());
    }
    
    /**
     * 格式化时间
     * @param obj Object
     * @return String [返回类型说明]
     * @see [类、类#方法、类#成员]
     */
    public static String formatDate(Object obj)
    {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(obj);
    }
    
    private static Date parseDate(String source)
    {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        try
        {
            return sdf.parse(source);
        }
        catch (ParseException e)
        {
            e.printStackTrace();
        }
        
        return null;
    }
    
    /**
     * 
     * 方法表述 获取当前时间的timestamp格式
     * @return Timestamp
     */
    public static Timestamp getTimestamp()
    {
        return getTimestamp(new Date().getTime());
    }
    
    /**
     * 
     * 方法表述 获取当前时间的timestamp格式
     * @param time long
     * @return Timestamp
     */
    public static Timestamp getTimestamp(long time)
    {
        return new Timestamp(time);
    }
    
    /**
     * <一句话功能简述>
     * <功能详细描述>
     * @param original String
     * @return String [返回类型说明]
     * @see [类、类#方法、类#成员]
     */
    public static String urlencode(String original)
    {
        try
        {
            //return URLEncoder.encode(original, "utf-8");
            //fixed: to comply with RFC-3986
            return URLEncoder.encode(original, "utf-8")
                    .replace("+", "%20")
                    .replace("*", "%2A")
                    .replace("%7E", "~");
        }
        catch (UnsupportedEncodingException e)
        {
            //Logger.e(e.toString());
        }
        return null;
    }
    
    /**
     * 
     * 方法表述 判断:是否有不存在的字段
     * @param source source
     * @param fields fields
     * @return boolean
     */
    public static boolean isValidateValue(String source, String fields)
    {
        boolean validate = true;
        String[] sourceArr = source.split(",");
        String[] fieldArr = fields.split(",");
        
        for (int i = 0; i < sourceArr.length; i++)
        {
            boolean fieldValidate = false;
            for (int j = 0; j < fieldArr.length; j++)
            {
                if (sourceArr[i].equals(fieldArr[j]))
                {
                    fieldValidate = true;
                    break;
                }
            }
            if (!fieldValidate)
            {
                validate = false;
                // 打印不存在字段
                logger.info("================= Fields: Request Parameter \""
                        + sourceArr[i] + "\" is not exist ===================");
                break;
            }
        }
        return validate;
    }
    
    /**
     * createFile
     * @param file file
     * @return boolean
     * @throws IOException IOException
     */
    public static boolean createFile(File file) throws IOException
    {
        if (!file.exists())
        {
            File parent = file.getParentFile();
            if (createDirector(parent))
            {
                return file.createNewFile();
            }
            return false;
        }
        return true;
    }
    
    /**
     * createDirector
     * @param dir dir
     * @return boolean
     */
    public static boolean createDirector(File dir)
    {
        return dir.mkdirs();
    }
    
    /**
     * 
     * 方法表述: 判断是否是数字
     * @param str str
     * @return boolean
     */
    public static boolean isNumeric(String str)
    {
        if (isNull(str))
        {
            return false;
        }
        return Pattern.matches("[0-9|\\.]*", str);
    }
    
    /**
     * 将数组转化为集合
     * @param arr 数组
     * @return List<T> 集合
     */
    public static <T> List<T> arrayToList(T[] arr)
    {
        List<T> list = new ArrayList<T>();
        
        int len = arr.length;
        for (int i = 0; i < len; i++)
        {
            list.add(arr[i]);
        }
        
        return list;
    }
    
    /**
     * 获取文件名不包括扩展名
     * @param name 文件名
     * @return 文件名不包括扩展名
     */
    public static String getFilenameWithoutExtension(String name)
    {
        int dot = name.indexOf('.');
        
        if (dot != -1)
        {
            name = name.substring(0, dot);
        }
        
        return name;
    }
    
    /**
     * 解析XML
     * @param file XML文件
     * @return XML文档对象
     * @throws IOException IOException
     * @throws JDOMException JDOMException
     */
    public static Document parseXML(File file) throws JDOMException,
            IOException
    {
        return new SAXBuilder().build(file);
    }
    
    /**
     * 格式化XML
     * @param file XML文件
     * @param encoding 编码
     * @param indent 缩进
     * @param lineSeparator 换行符
     * @return String 格式化的XML
     * @throws JDOMException JDOMException
     * @throws IOException IOException
     */
    public static String formatXML(File file, String encoding, String indent,
            String lineSeparator) throws JDOMException, IOException
    {
        Document document = new SAXBuilder().build(file);
        
        Format format = Format.getPrettyFormat();
        format.setEncoding(encoding);
        format.setIndent(indent);
        format.setLineSeparator(lineSeparator);
        
        XMLOutputter outputter = new XMLOutputter(format);
        return outputter.outputString(document);
    }
    
    /**
     * 格式化JSON
     * @param source JSON数据
     * @param indent 缩进
     * @param lineSeparator 换行符
     * @return 格式化的JSON
     */
    public static String formatJSON(String source, String indent,
            String lineSeparator)
    {
        StringBuffer strNew = new StringBuffer();
        int tabNum = 0;
        
        source = source.trim();
        
        int len = source.length();
        
        for (int i = 0; i < len; i++)
        {
            if (source.charAt(i) == '{')
            {
                strNew.append(lineSeparator);
                appendIndent(indent, strNew, tabNum);
                strNew.append(source.charAt(i));
                tabNum++;
                strNew.append(lineSeparator);
                appendIndent(indent, strNew, tabNum);
            }
            else if (source.charAt(i) == '}')
            {
                tabNum--;
                strNew.append(lineSeparator);
                appendIndent(indent, strNew, tabNum);
                strNew.append(source.charAt(i));
            }
            else if (source.charAt(i) == ',')
            {
                strNew.append(source.charAt(i));
                strNew.append(lineSeparator);
                appendIndent(indent, strNew, tabNum);
            }
            else
            {
                strNew.append(source.charAt(i));
            }
        }
        return strNew.toString();
    }
    
    /**
     * 添加缩进
     * @param indent 缩进
     * @param strNew 新字符串
     * @param tabNum 缩进数
     */
    private static void appendIndent(String indent, StringBuffer strNew,
            int tabNum)
    {
        while (tabNum-- > 0)
        {
            strNew.append(indent);
        }
    }
    
    /**
     * 转义换行符
     * @param source 源字符串
     * @return 目标字符串
     */
    public static String escapeNewLine(String source)
    {
    	source = source.replace(">", "&gt;").replace("<",
        "&lt;");
    	source = source.replace("&lt;br&gt;", "<br>");
    	return source;
    }
}
